AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include('shared.lua')

//make snpc hurt you
//have bounding box move w/ model
//have it make nicenice w/ npc_soldier

ENT.Alerted     = false
ENT.bleeds      = 0
ENT.StartHealth = 2600
ENT.PlayerFriendly = 0
ENT.AttackingMelee = false
ENT.State = 0 //1 is moving to enemy, 2 is staying put
ENT.BreathTime = 0
ENT.RoarTime = 0
ENT.FlameTime = 0
ENT.Enemy = NULL
ENT.BreathTime = 0
ENT.dead = false
ENT.DestAlt = 750
ENT.rocket_toggle = false;
ENT.MinChaseDistance = 1500
ENT.MinMeleeDistance = 650
ENT.MinRangeDistance = 2000
ENT.MinFloatDistance = 1000
ENT.MeleeAttacking = false
ENT.MeleeDamage = 150
ENT.MeleeTime = 0
ENT.dodgeleft = true
   
function ENT:Initialize()
	
   self:SetModel( "models/Combine_Helicopter.mdl" )	
   self.Entity:PhysicsInitBox( Vector(-100,-100,-100),Vector(100,100,100) )      -- Make us work with physics,  	
   self.Entity:SetMoveType( MOVETYPE_VPHYSICS )   --after all, gmod is a physics  	
   self.Entity:SetSolid( SOLID_BBOX )        -- Toolbox  
   self:CapabilitiesAdd( CAP_MOVE_FLY )
   self:SetHullType(HULL_LARGE)
   self:SetModel( "models/npc/dragon/npc_dragon.mdl" )	
   self:SetMaxYawSpeed( 10 )

   self:SetHealth(self.StartHealth)
   self.Enemy = NULL
   self:SetPos(self:GetPos() + Vector(0,0,500))
   self.FlameTime = CurTime() + 10
	local phys = self.Entity:GetPhysicsObject()  	
	if (phys:IsValid()) then 		
		phys:Wake()  
		phys:EnableGravity(false)
		phys:SetMass( phys:GetMass()/3 ) 
	end 
end
   
function ENT:OnTakeDamage(dmg)
    if dmg:GetDamage() < 30 then
		if dodgeleft == true then
			local phy = self:GetPhysicsObject()
			if phy:IsValid() then
				phy:ApplyForceCenter((self:GetRight() * -50000))
			end
		else
			local phy = self:GetPhysicsObject()
			if phy:IsValid() then
				phy:ApplyForceCenter((self:GetRight() * 50000))
			end
		end
	else
		dodgeleft = !dodgeleft
	end

   self:SetHealth(self:Health() - dmg:GetDamage())

   if dmg:GetAttacker():GetClass() != self:GetClass() && math.random(1,7) == 1 then
   	self:ResetEnemy()
   	self:AddEntityRelationship( dmg:GetAttacker(), 1, 10 )
   	self.Enemy = dmg:GetAttacker()
	//if math.random(1,8) == 1 then
   	//self.myturrent.Enemy = dmg:GetAttacker()
	//end
   end
   self.Alerted = true
   if self:Health() <= 0 && !self.dead then //run on death	
	print("DIED!!!")
	self.dead = true;
	self:KilledDan()
   end
end

function ENT:Think()
	local function EndFire()
		//self:SetSchedule(SCHED_IDLE_STAND);
	end
	local function EndMelee()
		self.MeleeAttacking = false
	end
	local function FireFlames()
		local shoot_vector = (self.Enemy:GetPos() - self:LocalToWorld(Vector(280,0,50)) )//+ Vector(math.random(-200,200),math.random(-200,200),math.random(-200,200)))
		shoot_vector:Normalize()
		local rocket = ents.Create("proj_dan_flamebreath")
		self:EmitSound("dragon/flame"..math.random(1,6)..".wav",500,100)
		rocket:SetPos(self:LocalToWorld(Vector(240,0,50)))
		rocket:SetAngles(shoot_vector:Angle())
		rocket:Activate()
		rocket:Spawn()
		local phy = rocket:GetPhysicsObject()
		if phy:IsValid() then
			phy:ApplyForceCenter((shoot_vector * 7500))
		end
		timer.Simple(3,EndFire);
	end
	local function HitTheFucker()
		local phy = self:GetPhysicsObject()
		if phy:IsValid() then
			phy:ApplyForceCenter((self:GetForward() * -80000))
		end
		self:EmitSound("dragon/tail"..math.random(1,4)..".wav",450,100)
		local entstoattack = ents.FindInSphere(self:LocalToWorld(Vector(120,0,-120)),200)
		for _,v in pairs(entstoattack) do
			if ( (v:IsNPC() || ( v:IsPlayer() && v:Alive())) && (v != self) && (v:GetClass() != self:GetClass()) || (v:GetClass() == "prop_physics")) then
				v:TakeDamage( self.MeleeDamage, self ) 
				self:EmitSound("dragon/hit"..math.random(1,3)..".wav",450,100)
			end
		end
		timer.Simple(2,EndMelee);
	end
	
	local function BiteTheFucker()
		local phy = self:GetPhysicsObject()
		if phy:IsValid() then
			phy:ApplyForceCenter((self:GetForward() * -80000))
		end
		local entstoattack = ents.FindInSphere(self:LocalToWorld(Vector(240,0,-100)),100)
		for _,v in pairs(entstoattack) do
			if ( (v:IsNPC() || ( v:IsPlayer() && v:Alive())) && (v != self) && (v:GetClass() != self:GetClass()) || (v:GetClass() == "prop_physics")) then
				v:TakeDamage( self.MeleeDamage * 2, self ) 
			end
		end
		timer.Simple(3,EndMelee);
	end

	if self.Enemy:IsValid() == false then
	self.Enemy = NULL
	elseif self.Enemy:Health(health) <= 0 then
	self.Enemy = NULL
	elseif self.Enemy == self then
	self.Enemy = NULL
	end

	if CurTime() > self.BreathTime then
		self.EmitSound(self,"dragon/flap"..math.random(1,3)..".wav",420,100)
		self.BreathTime = CurTime() + 2
	end
	
	//self.myturrent:SetPos(self:GetPos())	

	//print(self.TakingCover)
	if self:Health() > 0 && GetConVarNumber("ai_disabled") == 0 then

		if CurTime() > self.RoarTime then
			self.RoarTime = CurTime() + math.random(30,45)
			//kill our turrent
			self:EmitSound("dragon/roar"..math.random(1,2)..".wav",500,100)
			local bar = ents.Create("env_shake")
			bar:SetPos(self:GetPos())
			bar:SetKeyValue("amplitude","12")
			bar:SetKeyValue("radius","4000")
			bar:SetKeyValue("duration","3")
			bar:SetKeyValue("frequency","128")
			bar:Fire( "StartShake", 0, 0 )
		end
		
		//print( "Think start" );
		//Get all the npc's and other entities.
		local enttable = ents.FindByClass("npc_*")
		local monstertable = ents.FindByClass("monster_*")
		table.Add(monstertable,enttable)//merge

		//sort through each ent.
		for _, x in pairs(monstertable) do
			if (!ents) then print( "No Entities!" ); return end
			if (x:GetClass() != self:GetClass() && x:GetClass() != "npc_grenade_frag" && x:IsNPC()) then
				print(x)
				print("..is chassis enemy")
				if x:GetClass() != "npc_dragon" then
					x:AddEntityRelationship( self, 1, 10 )
				else
					x:AddEntityRelationship( self, 3, 10 )
				end
			end
		end

		//set fixed angles
		local phy = self:GetPhysicsObject()
		if phy:IsValid() then
			local velocity = phy:GetVelocity()
			phy:SetAngle( Angle(20,self:GetAngles().y,0) )
			phy:SetVelocity(velocity)
		end

		//self:FindEnemyDan()
		
		//set the turrents location to our own
		//self.myturrent:SetAngles(Angle(-(self:GetAngles().p),self.myturrent:GetAngles().y,0))

		if self.Enemy != NULL then 
				//apply movement
				//print("works")
				
				local wantedvector = (self.Enemy:GetPos() - self:GetPos() + Vector(0,0,150))
				local shootvector = (self.Enemy:GetPos() - self:GetPos() ) //+ Vector(0,0,80))
				local wantedangle = (self.Enemy:GetPos() - self:GetPos() + Vector(0,0,80)):Angle()
				local currentangle = Angle(20,self:GetAngles().y,0)
				local anglediff = self:GetAngleDiff(wantedangle.y,currentangle.y)
				local pitchdiff = self:GetAngleDiff(wantedangle.p,currentangle.p)
				local heightratio = (self.Enemy:GetPos().z - self:GetPos().z ) / self:GetPos():Distance(self.Enemy:GetPos())
				local distance_2d = self:GetPos():Distance(Vector(self.Enemy:GetPos().x,self.Enemy:GetPos().y,self:GetPos().z))
				
				if self:GetPos():Distance(self.Enemy:GetPos()) > self.MinChaseDistance || ( distance_2d < self.MinMeleeDistance && distance_2d > self.MinMeleeDistance/2) then
					//print("moving")
					local phy = self:GetPhysicsObject()
					if phy:IsValid() then
						phy:ApplyForceCenter((wantedvector:Normalize() * 50000))
					end
				end
				if distance_2d > self.MinFloatDistance then
					if self.DestAlt - 450 > self:GetPos().z then
						local phy = self:GetPhysicsObject()
						if phy:IsValid() then
							phy:ApplyForceCenter((Vector(0.15,0,1) * 7000))
						end
					elseif self.DestAlt + 300 < self:GetPos().z then
						local phy = self:GetPhysicsObject()
						if phy:IsValid() then
							phy:ApplyForceCenter((Vector(0.15,0,-1) * 7000))
						end
					end
				end
				if math.abs(anglediff) < 30 && self:GetPos():Distance(self.Enemy:GetPos()) < self.MinRangeDistance then
					if CurTime() > self.FlameTime then
						self.FlameTime = CurTime() + math.random(10,15)
						self:EmitSound("dragon/flameroar1.wav",500,100)
						self:SetSchedule(SCHED_RANGE_ATTACK1)	
						timer.Simple(1.1,FireFlames);
						timer.Simple(1.15,FireFlames);
						timer.Simple(1.2,FireFlames);
						timer.Simple(1.25,FireFlames);
						timer.Simple(1.3,FireFlames);
						timer.Simple(1.35,FireFlames);
						timer.Simple(1.4,FireFlames);
						timer.Simple(1.45,FireFlames);
						timer.Simple(1.5,FireFlames);
					end
				end
				if distance_2d < self.MinMeleeDistance/3.5 && self.MeleeAttacking == false then
					if CurTime() > self.MeleeTime then //&& math.random(1,3) != 3 then
						self.MeleeTime = CurTime() + 1
						self:EmitSound("dragon/angry"..math.random(1,4)..".wav",480,100)
						if math.random(1,2) == 1 then
							self:SetSchedule(SCHED_MELEE_ATTACK2)
						else
							self:SetSchedule(SCHED_SPECIAL_ATTACK1)
						end
						timer.Simple(0.5,HitTheFucker);
						self.MeleeAttacking = true
					//elseif CurTime() > self.MeleeTime then
					//	self.MeleeTime = CurTime() + 1.3
					//	self:EmitSound("dragon/bite_attack"..math.random(1,2)..".wav",480,100)
					//	self:SetSchedule(SCHED_MELEE_ATTACK1)
					//	timer.Simple(1,BiteTheFucker);
					//	self.MeleeAttacking = true
					end
				end
				
				if anglediff > 5 then
					print("turning positive")
					local phy = self:GetPhysicsObject()
					if phy:IsValid() then
						local velocity = phy:GetVelocity()
						phy:SetAngle( currentangle + Angle(0,3,0) )
						phy:SetVelocity(velocity)
					end
				elseif anglediff < -5 then
					print("turning negative")
					local phy = self:GetPhysicsObject()
					if phy:IsValid() then
						local velocity = phy:GetVelocity()
						phy:SetAngle( currentangle + Angle(0,-3,0) )
						phy:SetVelocity(velocity)
					end
				end
		else
			self:FindEnemyDan()
			self.MeleeAttacking = false
		end
	end
	
end

function ENT:SpawnBlood(dmg)
   	local bloodeffect = ents.Create( "info_particle_system" )
	if self.BleedsRed == true then
   		bloodeffect:SetKeyValue( "effect_name", "blood_impact_red_01" )
	else
		bloodeffect:SetKeyValue( "effect_name", "blood_impact_yellow_01")
	end
        bloodeffect:SetPos( dmg:GetDamagePosition() ) 
	bloodeffect:Spawn()
	bloodeffect:Activate() 
	bloodeffect:Fire( "Start", "", 0 )
	bloodeffect:Fire( "Kill", "", 0.1 )
end

function ENT:Touch( ent )
	if ent:GetClass() == "npc_grenade_rocket" then
		self:TakeDamage(200,ent)
		return
	end
	if self.State == 0 then
		ent:TakeDamage(100,self)
	end
end

function ENT:GetAngleDiff(angle1, angle2)
	local result = angle1 - angle2
	if result < -180 then
	result = result + 360
	end

	if result > 180 then
	result = result - 360
	end
	
	return result
end
   
function ENT:SelectSchedule()

if self.Enemy:IsValid() == false then
	self.Enemy = NULL
elseif self.Enemy:Health(health) <= 0 then
	self.Enemy = NULL
end

if self:Health() > 0 then
	local haslos = self:HasLOS()
	local distance = 0
	local enemy_pos = 0

	if self.Enemy:IsValid() == false then
	self.Enemy = NULL
	elseif self.Enemy:Health(health) <= 0 then
	self.Enemy = NULL
	elseif self.Enemy == self then
	self.Enemy = NULL
	end

	if self.Enemy == NULL then//no enemy
		//print( "No Enemy!" );
		//play idle sounds every now and then
	else
		//print( "Enemy!" );
		//print(self.Enemy)
		print(self.Enemy)
		print("..is chassis enemy")
		enemy_pos = self.Enemy:GetPos()
		distance = self:GetPos():Distance(enemy_pos)
		//distance = 4000
	        if distance > 2300 then// too far away
			self.State = 0//move to him
		elseif distance < 2300 && distance > 380 then//if in reasonable distance
			self.State = 1//stay put
		else//if too close 
			self.State = 1//stay put
		end
	end
end
end

function ENT:FindEnemyDan()
	local MyNearbyTargets = ents.FindInCone(self:GetPos(),self:GetForward(),1750,70)
	if (!MyNearbyTargets) then print( "No Targets!" ); return end
	for k,v in pairs(MyNearbyTargets) do
	    if v:Disposition(self) == 1 || (v:IsPlayer() && GetConVarNumber("ai_ignoreplayers") == 0) then
		self:ResetEnemy()
   		self:AddEntityRelationship( v, 1, 10 )
	    self.Enemy = v
		self:EmitSound("dragon/alert"..math.random(1,4)..".wav",480,100)
		self.Alerted = true
	      return
	    end
	end
	//if ClosestDistance == 4000 then
	//self:SetEnemy(NULL)
	//end
end

function ENT:StopHurtSounds()
end

function ENT:KilledDan()

	//create ragdoll
	local ragdoll = ents.Create( "prop_ragdoll" )
	ragdoll:SetModel( self:GetModel() )
	ragdoll:SetPos( self:GetPos() )
	ragdoll:SetAngles( self:GetAngles() )
	ragdoll:Spawn()
	ragdoll:SetSkin( self:GetSkin() )
	ragdoll:SetColor( self:GetColor() )
	ragdoll:SetMaterial( self:GetMaterial() )
	undo.AddEntity(ragdoll)
	if( GetConVarNumber("ai_keepragdolls") == 0 ) then
		ragdoll:SetCollisionGroup( 1 )//COLLISION_GROUP_DEBRIS )
		ragdoll:Fire( "FadeAndRemove", "", 15)
	end
	
	//my code
	undo.AddEntity(ragdoll)
	cleanup.ReplaceEntity(self,ragdoll)

	//ignight ragdoll if on fire.
	if self:IsOnFire() then ragdoll:Ignite( math.Rand( 8, 10 ), 0 ) end

	//position bones the same way.
        for i=1,128 do
		local bone = ragdoll:GetPhysicsObjectNum( i )
		if ValidEntity( bone ) then
			local bonepos, boneang = self:GetBonePosition( ragdoll:TranslatePhysBoneToBone( i ) )
			bone:SetPos( bonepos )
			bone:SetAngle( boneang )
		end
	end
	
	//kill our turrent
	local bar = ents.Create("env_shake")
	bar:SetPos(self:GetPos())
	bar:SetKeyValue("amplitude","8")
	bar:SetKeyValue("radius","4000")
	bar:SetKeyValue("duration","0.75")
	bar:SetKeyValue("frequency","128")
	bar:Fire( "StartShake", 0, 0 )
	
	//kill our turrent
	//self.myturrent:KilledDan()
	local blargity = EffectData()
	blargity:SetStart(self:GetPos())
	blargity:SetOrigin(self:GetPos())
	blargity:SetScale(500)
	WorldSound("dragon/death"..math.random(1,2)..".wav",self:GetPos(),450,100)
	//self:StopSound("npc/attack_helicopter/aheli_rotor_loop1.wav")
	self:Remove()
end

function ENT:ResetEnemy()
	local enttable = ents.FindByClass("npc_*")
	local monstertable = ents.FindByClass("monster_*")
	table.Add(monstertable,enttable)//merge

	//sort through each ent.
	for _, x in pairs(monstertable) do
		//print(x)
		if (!ents) then print( "No Entities!" ); return end
		if (x:GetClass() != self:GetClass()) then
			self:AddEntityRelationship( x, 2, 10 )
		end
		//print("Relationship Complete")
	end
	self:AddRelationship("player D_NU 10")
end

function ENT:OnRemove()
end

function ENT:HasLOS()
	if self.Enemy != NULL then
	//local shootpos = self:GetAimVector()*(self:GetPos():Distance(self.Enemy:GetPos())) + self:GetPos()
	//local shootpos = self.Enemy:GetPos()
	local tracedata = {}

	tracedata.start = self:GetPos()
	tracedata.endpos = self.Enemy:GetPos()
	tracedata.filter = self

	local trace = util.TraceLine(tracedata)
	if trace.HitWorld == false then
		return true
	else 
		return false
	end
	end
	print ("no enemy!")
	return false
end